<?php

namespace app\base\command;


use app\base\model\RedianData;
use app\base\model\RedianTask;
use app\base\service\TaskService;
use app\base\service\WsSendService;
use think\admin\Command;
use think\console\Input;
use think\console\Output;
use think\Exception;

/**
 * 定时推送处理
 * Class SmsNum
 * @package app\common\command
 */
class CrontabPush extends Command
{

    protected $input;
    protected $output;

    /**
     * 配置指令
     */
    protected function configure()
    {
        $this->setName('base:CrontabPush')
            ->addArgument('action', 1, 'start|stop|restart|reload|status|connections')
            ->setDescription('定时推送处理');
    }

    protected function execute(Input $input, Output $output)
    {
        $this->input = $input;
        $this->output = $output;
        $output->info("定时推送处理");
        // 获取所有启用的推送计划及7天内的计划

        $schedules = $this->app->db->name("redian_push_schedule")->where('status', 1)->whereMonth('create_at')->select();

        foreach ($schedules as $schedule) {
            if ($this->shouldPush($schedule)) {
                try {
                    $this->handlePush($schedule);
                } catch (\Exception $e) {
                    $output->info("推送失败_{$schedule['id']}：{$e->getMessage()}");
                    $this->app->log->error("推送失败_{$schedule['id']}：{$e->getMessage()}");
                }
            }
        }


    }

    // 判断是否需要推送
    private function shouldPush($schedule)
    {
        //判断该计划的所有推送条数是否已完成
        $pushd_num = $this->app->db->name("redian_data")
            ->where([
                'push_schedule_id'=>$schedule['id'],
                'is_flish'=>1,
            ])->count();
        if($pushd_num>=$schedule['push_num']){
            $this->app->db->name("redian_push_schedule")->where(['id'=>$schedule['id']])->update(['status'=>2]);
            sleep(10);
            //同步查询所有计划是否已推送完成
            $c = $this->app->db->name("redian_push_schedule")->where(['task_id'=>$schedule['task_id']])
                ->where('status','<>',2)->count();
            $this->output->info("推送_{$schedule['id']}同步查询所有计划是否已推送完成$c-{$schedule['task_id']}");
            if($c==0){
                $status = RedianTask::mQuery()->where([ "id"=>$schedule['task_id']])->value("status");
                if($status!=0){
                    $status =1;
                }
                $this->app->db->name("redian_task")->where(['id'=>$schedule['task_id']])->update(['progress'=>7,'status'=>$status]);
            }




            $this->output->info("推送_{$schedule['id']}已达到设置推送数量,计划已结束");
            return false;
        }

        if ($schedule['schedule_type'] == 1) { // 每日时段
            $current = time();
            $schedule_values  = explode(',', $schedule['schedule_value']);
            $star_time = strtotime(date("Y-m-d").$schedule_values[0]);
            $end_time = strtotime(date("Y-m-d").$schedule_values[1]);
            if($current>$star_time && $current<$end_time){
                return true;
            }else{
                return false;
            }
        } else { // 间隔分钟
            return time() >= strtotime($schedule['next_push']);
        }
    }

    // 执行推送操作
    private function handlePush($schedule)
    {



        //判断设备是否在线
        $device = $this->app->db->name("ai_device")->where(['id'=>$schedule['target_device']])->find();

        if($device){
            if($device['status']==0){
                $this->app->db->name("redian_push_log")->insert([
                    'schedule_id' => $schedule['id'],
                    'task_id' => $schedule['task_id'],
                    'user_id' => $schedule['user_id'],
                    'error_msg' => "设备不在线",
                    'status'=>0
                ]);
                $this->output->info("推送失败_{$schedule['id']}：设备不在线");
                return false;
            }
            if($device['work_status']==2 && (time()-strtotime($device['last_run_time']))<1800){
                $this->app->db->name("redian_push_log")->insert([
                    'schedule_id' => $schedule['id'],
                    'task_id' => $schedule['task_id'],
                    'user_id' => $schedule['user_id'],
                    'error_msg' => "设备繁忙",
                    'status'=>0
                ]);
                $this->output->info("推送失败_{$schedule['id']}：设备繁忙");
                return false;
            }


        }
        // 开启事务
        $this->app->db->startTrans();
        try {
            // 获取待推送数据（按创建时间排序）
            $dataIds = $this->app->db->name("redian_data")
                ->where([
                    'task_id'=>$schedule['task_id'],
                    'is_flish'=>0,
                    'video_status'=>3
                ])->where('push_num','<',6)->whereTime('push_time','<',date('Y-m-d H:i:s',time()-1000))->limit(0,1)->column('id');
            if (empty($dataIds)) {
                // 提交事务
                $c = $this->app->db->name("redian_data")
                    ->where([
                        'task_id'=>$schedule['task_id'],
                        'is_flish'=>0,
                        'video_status'=>3
                    ])->where('push_num','<',6)->count();

                if($c==0){
                    $this->app->db->name("redian_push_schedule")->where(['id'=>$schedule['id']])->update(['status'=>2]);
                    sleep(10);
                    //同步查询所有计划是否已推送完成
                    $c = $this->app->db->name("redian_push_schedule")->where(['task_id'=>$schedule['task_id']])
                        ->where('status','<>',2)->count();
                    $c = $c-1;
                    $this->output->info("推送_{$schedule['id']}同步查询所有计划是否已推送完成$c-{$schedule['task_id']}");
                    if($c<0){
                        $this->app->db->name("redian_task")->where(['id'=>$schedule['task_id']])->update(['progress'=>7,'status'=>1]);
                    }
                    $this->app->db->commit();
                }


                $this->output->info("推送失败_{$schedule['id']}：没有可推送的数据");
               // $this->app->log->error("推送失败_{$schedule['id']}：没有可推送的数据");
                throw new Exception('没有可推送的数据');
            }
            //获取对应平台执行脚本
            $run_script_ids = json_decode($schedule['run_script'],true);
            $script_files = $this->app->db->name("script_confg")->whereIn('id',$run_script_ids)->column('name');
            if(isset($script_files[0])){
                $script_file = $script_files[0];
                $next_script_file = "";
                if(isset($script_files[1])){
                    $next_script_file = $script_files[1];
                }
                $this->output->info("推送数据脚本_{$schedule['id']}：{$script_file}");
                foreach ($dataIds as $dataId){
                    $content = [
                        'type'=>1,
                        'script_files'=>$script_files,
                        'script_file'=>$script_file,
                        'next_script_file'=>$next_script_file,
                        'data_id'=>$dataId,
                        'is_update'=>1
                    ];
                    WsSendService::instance()->send($schedule['target_device'],1,$content);

                    $this->output->info("推送_{$schedule['id']}数据：".json_encode($content));
                    $this->app->db->name("redian_push_log")->insert([
                        'schedule_id' => $schedule['id'],
                        'task_id' => $schedule['task_id'],
                        'user_id' => $schedule['user_id'],
                        'status'=>1,
                        'data_id'=>$dataId
                    ]);
                }
            }




            // 更新下次推送时间
            if ($schedule['schedule_type'] == 2) {
                // 按分钟推送
                $next = strtotime("+{$schedule['schedule_value']} minutes");
                $this->app->db->name("redian_push_schedule")->where(['id'=>$schedule['id']])->inc('pushd_num',1)->update([
                    'last_push'=>date('Y-m-d H:i:s'),
                    'next_push' => date('Y-m-d H:i:s', $next)
                ]);


            }
            //将设备设置成繁忙
            $this->app->db->name("ai_device")->where(['id'=>$schedule['target_device']])->update([
                'work_status'=>2,
                'last_run_time' => date('Y-m-d H:i:s')
            ]);
            // 更新推送次数及数据推送的设备 平台
            $this->app->db->name("redian_data")->whereIn('id',$dataIds)->inc('push_num',1)->update([
                'is_push'=>1,
                'schedule_id'=>$schedule['target_device'],
                'platform'=>$schedule['platform'],
                'run_script'=>json_encode($this->app->db->name("script_confg")->whereIn('id',$run_script_ids)->column('name')),
                'push_time'=>date('Y-m-d H:i:s'),
                'push_schedule_id'=>$schedule['id']
            ]);

            $this->output->info("推送_{$schedule['id']}：成功");
            // 提交事务
            $this->app->db->commit();
        } catch (\Exception $e) {
            $this->app->db->rollback();
            $this->output->info("推送失败_{$schedule['id']}：{$e->getMessage()}");
          //  $this->app->log->error("推送失败_{$schedule['id']}：{$e->getMessage()}");
            throw $e;
        }
    }



}
